<?php
require_once dirname(__FILE__) . '/../../bootstrap/unit.php';

class unit_MemberTest extends WildlivePHPUnitTestCase
{

  private function loadFixtureSet001 ()
  {
    $this->loadFixtures('address.yml', 'bank_account.yml', 'country.yml', 'member.yml', 'organizational_entity.yml', 'organizational_member_data.yml', 
    'organizational_unit.yml', 'personal_member_data.yml', 'phone_number.yml', 'woggle.yml');
  }

  private function loadFixtureSet002 ()
  {
    // Resigned member
    $this->loadFixtures('address.yml', 'bank_account.yml', 'country.yml', 'member.yml', 'organizational_entity.yml', 
    'organizational_member_data_resigned.yml', 'organizational_unit.yml', 'personal_member_data.yml', 'phone_number.yml', 'woggle.yml');
  }

  /**
   * @return Member
   */
  private function getMember ()
  {
    return MemberTable::getInstance()->findOneByLastName('Lenkeit');
  }

  /**
   * @return Address
   */
  private function getNewAddress ()
  {
    $address = new Address();
    $address->setStreet('Test Straße');
    $address->setStreetNumber('99');
    $address->setZipCode('6789');
    $address->setCity('Test-Stadt');
    $address->setCountry(CountryTable::getInstance()->findAll()->getFirst());
    return $address;
  }

  /**
   * @return PhoneNumber
   */
  private function getNewPhoneNumber ()
  {
    $phone_number = new PhoneNumber();
    $phone_number->setAreaCode('6789');
    $phone_number->setCallThrough('7890');
    $phone_number->setType('fax');
    $phone_number->setCountry(CountryTable::getInstance()->findAll()->getFirst());
    return $phone_number;
  }

  public function testGetWoggleShouldReturnWoggleInstanceOfAssignedWoggle ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $woggle = $member->getWoggle();
    $this->assertInstanceOf('Woggle', $woggle);
    $this->assertEquals('Rot', $woggle->getName());
  }

  public function testSetWoggleShouldSetWoggleWithWoggleInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    // Set woggle
    $woggle = WoggleTable::getInstance()->findOneByName('Blau');
    $member->setWoggle($woggle);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $this->assertEquals($woggle->getId(), $member->getWoggleId());
  }

  public static function providerInvalidArgumentsForSetWoggle ()
  {
    return array(array("string"), array(array()), array(new stdClass()), array(true));
  }

  public static function providerTrueAndFalse ()
  {
    return array(array(true), array(false));
  }

  public static function providerOneAndZero ()
  {
    return array(array(0), array(1));
  }

  public function testSetWoggleShouldSetWoggleWithWoggleId ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    // Set woggle
    $woggle = WoggleTable::getInstance()->findOneByName('Blau');
    $woggle_id = $woggle->getId();
    $member->setWoggle($woggle_id);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $this->assertEquals($woggle->getId(), $member->getWoggleId());
  }

  /**
   * @dataProvider providerInvalidArgumentsForSetWoggle
   * @expectedException InvalidArgumentException
   */
  public function testSetWoggleShouldThrowExecptionForInvalidArgument ($invalidParam)
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    // Set woggle
    $member->setWoggle($invalidParam);
    $member->save();
  }

  public function testGetOrganizationalDataShouldReturnInsanceOfOrganizationalMemberData ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $organizational_data = $member->getOrganizationalData();
    $this->assertInstanceOf('OrganizationalMemberData', $organizational_data);
    $this->assertEquals($member->getId(), $organizational_data->getMemberId());
  }

  public function testHasOrganizationalDataShouldReturnTrueIfAssignedToMember ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $this->assertTrue($member->hasOrganizationalData());
  }

  public function testHasOrganizationalDataShouldReturnFalseIfNotAssignedToMember ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $member->getOrganizationalData()->delete();
    
    // Reload member
    $member = $this->getMember();
    $this->assertFalse($member->hasOrganizationalData());
  }

  public function testHasPersonalDataShouldReturnTrueIfAssignedToMember ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $this->assertTrue($member->hasPersonalData());
  }

  public function testHasPersonalDataShouldReturnFalseIfNotAssignedToMember ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $member->getPersonalData()->delete();
    
    // Reload member
    $member = $this->getMember();
    $this->assertFalse($member->hasPersonalData());
  }

  public function testGetAddressesShouldReturnDoctrineCollectionWithAssignedAddresses ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $addresses = $member->getAddresses();
    $this->assertInstanceOf('Doctrine_Collection', $addresses);
    $this->assertEquals(2, count($addresses));
  }

  public function testAttachAddressShouldAssignAddressToMemberForAddressInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $address = $this->getNewAddress();
    
    $num_addresses_before = count(AddressTable::getInstance()->findAll());
    $member->attachAddress($address);
    $member->save();
    $num_addresses_after = count(AddressTable::getInstance()->findAll());
    $this->assertEquals($num_addresses_before + 1, $num_addresses_after);
    
    // Reload member
    $member = $this->getMember();
    $addresses = $member->getAddresses();
    $this->assertEquals(3, count($addresses));
  }

  public function testAttachAddressShouldAssignAddressToMemberForAddressId ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $address = $this->getNewAddress();
    $address->save();
    
    $member->attachAddress($address->getId());
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $addresses = $member->getAddresses();
    $this->assertEquals(3, count($addresses));
  }

  public function testDetachAddressShouldUnassignAddressFromMemberForAddressInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $this->assertInstanceOf('Doctrine_Collection', $member->getAddresses());
    $address = $member->getAddresses()->getFirst();
    
    $num_addresses_before = count(AddressTable::getInstance()->findAll());
    $member->detachAddress($address);
    $member->save();
    $num_addresses_after = count(AddressTable::getInstance()->findAll());
    $this->assertEquals($num_addresses_before, $num_addresses_after); // Detach shouldn't delete, just detach
    

    // Reload member
    $member = $this->getMember();
    $num_addresses = count($member->getAddresses());
    $this->assertEquals(1, $num_addresses);
  }

  public function testDetachAddressShouldUnassignAddressFromMemberForAddressId ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $this->assertInstanceOf('Doctrine_Collection', $member->getAddresses());
    $address = $member->getAddresses()->getFirst();
    $this->assertInstanceOf('Address', $address);
    
    $num_addresses_before = count(AddressTable::getInstance()->findAll());
    $member->detachAddress($address->getId());
    $member->save();
    $num_addresses_after = count(AddressTable::getInstance()->findAll());
    $this->assertEquals($num_addresses_before, $num_addresses_after); // Detach shouldn't delete, just detach
    

    // Reload member
    $member = $this->getMember();
    $num_addresses = count($member->getAddresses());
    $this->assertEquals(1, $num_addresses);
  }

  public function testGetPhoneNumbersShouldReturnDoctrineCollectionWithAssignedPhoneNumbers ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $phone_numbers = $member->getPhoneNumbers();
    $this->assertInstanceOf('Doctrine_Collection', $phone_numbers);
    $this->assertEquals(2, count($phone_numbers));
  }

  public function testAttachPhoneNumberShouldAssignPhoneNumberToMemberForPhoneNumberInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $phone_number = $this->getNewPhoneNumber();
    
    $num_phone_numbers_before = count(PhoneNumberTable::getInstance()->findAll());
    $member->attachPhoneNumber($phone_number);
    $member->save();
    $num_phone_numbers_after = count(PhoneNumberTable::getInstance()->findAll());
    $this->assertEquals($num_phone_numbers_before + 1, $num_phone_numbers_after);
    
    // Reload member
    $member = $this->getMember();
    $phone_numbers = $member->getPhoneNumbers();
    $this->assertEquals(3, count($phone_numbers));
  }

  public function testAttachPhoneNumberShouldAssignPhoneNumberToMemberForPhoneNumberId ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $phone_number = $this->getNewPhoneNumber();
    $phone_number->save();
    
    $member->attachPhoneNumber($phone_number->getId());
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $phone_numbers = $member->getPhoneNumbers();
    $this->assertEquals(3, count($phone_numbers));
  }

  public function testDetachPhoneNumberShouldUnassignPhoneNumberFromMemberForPhoneNumberInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $this->assertInstanceOf('Doctrine_Collection', $member->getPhoneNumbers());
    $phone_number = $member->getPhoneNumbers()->getFirst();
    
    $num_phone_numbers_before = count(PhoneNumberTable::getInstance()->findAll());
    $member->detachPhoneNumber($phone_number);
    $member->save();
    $num_phone_numbers_after = count(PhoneNumberTable::getInstance()->findAll());
    $this->assertEquals($num_phone_numbers_before, $num_phone_numbers_after); // Detach shouldn't delete, just detach
    

    // Reload member
    $member = $this->getMember();
    $num_phone_numbers = count($member->getPhoneNumbers());
    $this->assertEquals(1, $num_phone_numbers);
  }

  public function testDetachPhoneNumberShouldUnassignPhoneNumberFromMemberForPhoneNumberId ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $this->assertInstanceOf('Doctrine_Collection', $member->getPhoneNumbers());
    $phone_number = $member->getPhoneNumbers()->getFirst();
    $this->assertInstanceOf('PhoneNumber', $phone_number);
    
    $num_phone_numbers_before = count(PhoneNumberTable::getInstance()->findAll());
    $member->detachPhoneNumber($phone_number->getId());
    $member->save();
    $num_phone_numbers_after = count(PhoneNumberTable::getInstance()->findAll());
    $this->assertEquals($num_phone_numbers_before, $num_phone_numbers_after); // Detach shouldn't delete, just detach
    

    // Reload member
    $member = $this->getMember();
    $num_phone_numbers = count($member->getPhoneNumbers());
    $this->assertEquals(1, $num_phone_numbers);
  }

  public function testGetOrganizationalUnitShouldReturnOrganizationalUnitInstanceOfAssignedOrganizationalUnit ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $organizational_unit = $member->getOrganizationalUnit();
    $this->assertInstanceOf('OrganizationalUnit', $organizational_unit);
    $this->assertEquals('Stamm Rot', $organizational_unit->getName());
  }

  public function testSetOrganizationalUnitShouldSetOrganizationalUnitWithOrganizationalUnitInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    // Set organizational unit
    $organizational_unit = OrganizationalUnitTable::getInstance()->findOneByName('Stamm Blau');
    $member->setOrganizationalUnit($organizational_unit);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $this->assertEquals($organizational_unit->getId(), $member->getOrganizationalUnitId());
  }

  public function testSetOrganizationalUnitShouldSetOrganizationalUnitWithOrganizationalUnitId ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    // Set organizational unit
    $organizational_unit = OrganizationalUnitTable::getInstance()->findOneByName('Stamm Blau');
    $member->setOrganizationalUnit($organizational_unit->getId());
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $this->assertEquals($organizational_unit->getId(), $member->getOrganizationalUnitId());
  }

  public function testGetDateOfJoiningShouldReturnDateTimeInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $expected = new DateTime('2000-01-01');
    
    $date_of_joining = $member->getDateOfJoining();
    $this->assertEquals($expected, $date_of_joining);
  }

  public function testSetDateOfJoiningShouldSetDateOfJoiningForDateTimeInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $expected = new DateTime('2001-01-01');
    
    $member->setDateOfJoining($expected);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $actual = $member->getDateOfJoining();
    $this->assertEquals($expected, $actual);
  }

  public function testSetDateOfJoiningShouldSetDateOfJoiningForTimestamp ()
  {
    //This would fix the problem but actually, sf should take care of this
    //date_default_timezone_set('Europe/London');
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $timestamp = mktime(0, 0, 0, 1, 1, 2001); // 2001-01-01
    

    $member->setDateOfJoining($timestamp);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $actual = $member->getDateOfJoining();
    $this->assertEquals($timestamp, $actual->getTimestamp());
  }

  public function testGetDateOfResignationShouldReturnDateTimeInstance ()
  {
    // Initialize data
    $this->loadFixtureSet002();
    $member = $this->getMember();
    $expected = new DateTime('2001-01-01');
    
    $date_of_resignation = $member->getDateOfResignation();
    $this->assertEquals($expected, $date_of_resignation);
  }

  public function testSetDateOfResignationShouldSetDateOfResignationForDateTimeInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $expected = new DateTime('2002-01-01');
    
    $member->setDateOfResignation($expected);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $actual = $member->getDateOfResignation();
    $this->assertEquals($expected, $actual);
  }

  public function testSetDateOfResignationShouldSetDateOfResignationForTimestamp ()
  {
    //This would fix the problem but actually, sf should take care of this
    //date_default_timezone_set('Europe/London');
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $timestamp = mktime(0, 0, 0, 1, 1, 2002); // 2001-01-01
    

    $member->setDateOfResignation($timestamp);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $actual = $member->getDateOfResignation();
    $this->assertEquals($timestamp, $actual->getTimestamp());
  }

  public function testHasScarfShouldReturnTrueIfMemberHasScarf ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $this->assertTrue($member->hasScarf());
  }

  public function testHasScarfShouldReturnFlaseIfMemberHasNotScarf ()
  {
    // Initialize data
    $this->loadFixtureSet002();
    $member = $this->getMember();
    
    $this->assertFalse($member->hasScarf());
  }

  /**
   * @dataProvider providerTrueAndFalse
   */
  public function testSetScarfShouldAcceptTrueAndFalse ($flag)
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $member->setScarf($flag);
    
    // Reload member
    $member = $this->getMember();
    if ($flag === true)
    {
      $this->assertTrue($member->hasScarf());
    }
    else
    {
      $this->assertFalse($member->hasScarf());
    }
  }

  /**
   * @dataProvider providerOneAndZero
   */
  public function testSetScarfShouldAcceptOneAndZero ($flag)
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $member->setScarf($flag);
    
    // Reload member
    $member = $this->getMember();
    if ($flag === 1)
    {
      $this->assertTrue($member->hasScarf());
    }
    else
    {
      $this->assertFalse($member->hasScarf());
    }
  }

  public function testGetEmailAddressShouldReturnAssignedEmailAddress ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    
    $this->assertEquals('user@host.com', $member->getEmailAddress());
  }

  public function testSetEmailAddressShouldAcceptStringAndChangeAssigned ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $expected = 'user2@host.de';
    
    $member->setEmailAddress($expected);
    
    // Reload member
    $member = $this->getMember();
    $this->assertEquals($expected, $member->getEmailAddress());
  }

  public function testGetDateOfBirthShouldReturnDateTimeInstance ()
  {
    // Initialize data
    $this->loadFixtureSet002();
    $member = $this->getMember();
    $expected = new DateTime('1995-01-01');
    
    $date_of_birth = $member->getDateOfBirth();
    $this->assertEquals($expected, $date_of_birth);
  }

  public function testSetDateOfBirthShouldSetDateOfBirthForDateTimeInstance ()
  {
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $expected = new DateTime('1996-01-01');
    
    $member->setDateOfBirth($expected);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $actual = $member->getDateOfBirth();
    $this->assertEquals($expected, $actual);
  }

  public function testSetDateOfBirthShouldSetDateOfBirthForTimestamp ()
  {
    //This would fix the problem but actually, sf should take care of this
    //date_default_timezone_set('Europe/London');
    // Initialize data
    $this->loadFixtureSet001();
    $member = $this->getMember();
    $timestamp = mktime(0, 0, 0, 1, 1, 2002); // 2001-01-01
    

    $member->setDateOfBirth($timestamp);
    $member->save();
    
    // Reload member
    $member = $this->getMember();
    $actual = $member->getDateOfBirth();
    $this->assertEquals($timestamp, $actual->getTimestamp());
  }
}